package com.yanceysong;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RefreshQuestionSortAndBackup {
    public static void main(String[] args) {
        try {
            System.out.println("=== CodeTop100 题目排序更新工具启动 ===");

            Path baseDir = Paths.get("src", "main", "java", "com", "yanceysong");
            Path codeTopDir = baseDir.resolve("codetop");

            // Step 1: Fetch current problem order from API
            List<Question> apiQuestions = getLatestQuestions();
            System.out.println("获取到 " + apiQuestions.size() + " 个题目");

            // Step 2: Scan existing files
            Map<String, FileData> existingFiles = scanExistingFiles(codeTopDir);
            System.out.println("扫描到 " + existingFiles.size() + " 个现有文件");

            // Step 3: Create backup
            backupOriginalFolder(codeTopDir);

            // Step 4: Create new directory structure
            Path newDir = createNewStructure(baseDir, apiQuestions, existingFiles);

            // Step 5: Replace old with new
            replaceOldWithNew(codeTopDir, newDir);

            System.out.println("=== 更新完成 ===");
        } catch (Exception e) {
            System.err.println("更新过程中发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 获取API最新排序
     */
    private static List<Question> getLatestQuestions() {
        String url = "https://codetop.cc/api/questions/?page=%d&size=20&search=&ordering=-frequency";
        ArrayList<Question> questionsSortList = new ArrayList<>();
        System.out.println("开始获取API数据...");

        // 获取5页，每页20道题，总共100道
        for (int i = 1; i <= 5; i++) {
            String finalUrl = String.format(url, i);
            System.out.println("正在获取第" + (i + 1) + "页: " + finalUrl);
            try {
                String result = HttpUtil.get(finalUrl);
                JSONObject jsonObject = JSON.parseObject(result);
                JSONArray list = jsonObject.getJSONArray("list");

                List<Question> pageQuestions = list.stream()
                        .map(obj -> ((JSONObject) obj).getJSONObject("leetcode"))
                        .filter(Objects::nonNull)
                        .map(data -> {
                            String title = data.getString("title");
                            String leetCodeId = data.getString("frontend_question_id");
                            if (title == null || title.trim().isEmpty() || leetCodeId == null || leetCodeId.trim().isEmpty()) {
                                return null;
                            }
                            String level = getLevel(data.getInteger("level"));
                            String className = processClassName(title);
                            return new Question(level, className, className, leetCodeId);
                        })
                        .filter(Objects::nonNull)
                        .toList();
                questionsSortList.addAll(pageQuestions);
            } catch (Exception e) {
                System.err.println("获取第" + (i + 1) + "页数据失败: " + e.getMessage());
            }
        }
        return questionsSortList;
    }

    private static Map<String, FileData> scanExistingFiles(Path codeTopDir) throws IOException {
        Map<String, FileData> fileMap = new HashMap<>();
        Pattern CLASS_NAME_PATTERN = Pattern.compile("public class (S\\d+_[A-Za-z]+_[^_]+_[^\\s{]+)");
        Pattern LEETCODE_ID_PATTERN = Pattern.compile("S\\d+_[A-Za-z]+_([^_]+)_");

        if (!Files.exists(codeTopDir)) {
            System.out.println("codetop文件夹不存在，将创建新的文件结构");
            return fileMap;
        }

        Files.walk(codeTopDir)
                .filter(Files::isRegularFile)
                .filter(p -> p.toString().endsWith(".java"))
                .forEach(p -> {
                    try {
                        String content = Files.readString(p);
                        Matcher classMatcher = CLASS_NAME_PATTERN.matcher(content);
                        if (classMatcher.find()) {
                            String oldClassName = classMatcher.group(1);
                            Matcher idMatcher = LEETCODE_ID_PATTERN.matcher(oldClassName);
                            if (idMatcher.find()) {
                                String leetcodeId = idMatcher.group(1);
                                FileData data = new FileData(oldClassName, leetcodeId, p, content);
                                fileMap.put(processClassName(leetcodeId), data);
                            }
                        }
                    } catch (Exception e) {
                        System.err.println("解析文件失败: " + p + ", 错误: " + e.getMessage());
                    }
                });
        return fileMap;
    }

    private static void backupOriginalFolder(Path codeTopDir) throws IOException {
        if (!Files.exists(codeTopDir)) {
            return;
        }

        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        // 将备份文件夹创建在项目根目录，以避免编译错误
        Path backupDir = Paths.get("codetop_backup_" + timestamp);

        System.out.println("备份原文件夹到: " + backupDir);
        copyDirectory(codeTopDir, backupDir);
    }

    private static void copyDirectory(Path source, Path target) throws IOException {
        Files.walk(source)
                .forEach(sourcePath -> {
                    try {
                        Path targetPath = target.resolve(source.relativize(sourcePath));
                        if (Files.isDirectory(sourcePath)) {
                            Files.createDirectories(targetPath);
                        } else {
                            Files.createDirectories(targetPath.getParent());
                            Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });
    }

    private static Path createNewStructure(Path baseDir,
                                           List<Question> apiQuestions,
                                           Map<String, FileData> existingFiles) throws IOException {
        Path newDir = baseDir.resolve("codetop_new");

        if (Files.exists(newDir)) {
            deleteDirectory(newDir);
        }
        Files.createDirectories(newDir);

        System.out.println("创建新的文件结构...");
        int rank = 1;
        for (Question question : apiQuestions) {
            String newFileName = String.format("S%d_%s_%s_%s.java",
                    rank,
                    question.level(),
                    processClassName(question.leetCodeId()),
                    question.name());

            Path subDir = getSubdirectory(newDir, rank);
            Path newFilePath = subDir.resolve(newFileName);

            if (existingFiles.containsKey(processClassName(question.leetCodeId()))) {
                FileData existing = existingFiles.get(processClassName(question.leetCodeId()));
                updateFileContent(existing, newFilePath, question, rank);
                System.out.println("更新: " + newFileName);
            } else {
                createNewClassFile(newFilePath, question, rank);
                System.out.println("新建: " + newFileName);
            }
            rank++;
        }
        return newDir;
    }

    private static void updateFileContent(FileData existing, Path newPath, Question question, int rank) throws IOException {
        String content = existing.content();

        // 更新包名
        String newPackage = getPackageName(rank);
        content = content.replaceFirst("package com\\.yanceysong\\.codetop\\.[^;]+;",
                "package " + newPackage + ";");

        // 更新类名
        String oldClassName = existing.oldClassName();
        String newClassName = String.format("S%d_%s_%s_%s",
                rank, question.level(), processClassName(question.leetCodeId()), question.className());

        // Safely replace all occurrences of the old class name
        content = content.replaceAll(Pattern.quote(oldClassName), newClassName);

        Files.createDirectories(newPath.getParent());
        Files.writeString(newPath, content);
    }

    private static void createNewClassFile(Path filePath, Question question, int rank) throws IOException {
        String className = String.format("S%d_%s_%s_%s",
                rank, question.level(), processClassName(question.leetCodeId()), question.className());
        String packageName = getPackageName(rank);

        String content = String.format("""
                        package %s;
                        
                        /**
                         * @ClassName %s
                         * @Description LeetCode %s - %s
                         * @date %s
                         * @Author yanceysong
                         * @Version 1.0
                         */
                        public class %s {
                            /**
                             * TODO: 实现题目解法
                             * LeetCode %s: %s
                             * 难度: %s
                             */
                            public void solve() {
                                // TODO: 实现解法
                            }
                        
                            public static void main(String[] args) {
                                %s solution = new %s();
                        
                                System.out.println("=== %s 测试开始 ===");
                        
                                // TODO: 添加测试用例
                        
                                System.out.println("=== 测试完成 ===");
                            }
                        }
                        """, packageName, className, question.leetCodeId(), question.name(),
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/M/d HH:mm")),
                className, question.leetCodeId(), question.name(), question.level(),
                className, className, question.name());

        Files.createDirectories(filePath.getParent());
        Files.writeString(filePath, content);
    }

    private static void replaceOldWithNew(Path oldDir, Path newDir) throws IOException {
        if (Files.exists(oldDir)) {
            deleteDirectory(oldDir);
        }
        Files.move(newDir, oldDir);
        System.out.println("文件结构更新完成");
    }

    private static void deleteDirectory(Path path) throws IOException {
        if (Files.exists(path)) {
            Files.walk(path)
                    .sorted(Comparator.reverseOrder())
                    .forEach(p -> {
                        try {
                            Files.delete(p);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    });
        }
    }

    // Helper methods
    private static Path getSubdirectory(Path base, int index) throws IOException {
        int start = ((index - 1) / 10) * 10 + 1;
        String dirName = "s" + start + "_s" + (start + 9);
        Path dir = base.resolve(dirName);
        Files.createDirectories(dir);
        return dir;
    }

    private static String getPackageName(int index) {
        int start = ((index - 1) / 10) * 10 + 1;
        String dirName = "s" + start + "_s" + (start + 9);
        return "com.yanceysong.codetop." + dirName;
    }

    private static String getLevel(Integer level) {
        return switch (level) {
            case 1 -> "Easy";
            case 3 -> "Hard";
            default -> "Mid";
        };
    }

    private static String processClassName(String title) {
        return title.replaceAll("[\\s\\-()\\[\\]{}.,，。：:；;！!？? \"']+", "_")
                .replaceAll("_+", "_")
                .replaceAll("^_|_$", "");
    }

    // Record classes for data handling
    record Question(String level, String name, String className, String leetCodeId) {
    }

    record FileData(String oldClassName, String leetcodeId, Path path, String content) {
    }
}
